/*    

    bobbietalk - a visual programming environment for toy robotics

    Copyright (C) 2013  Roberto Tiella

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/
package bobbietalk.semantics.interpreter.robots.remote;

import bobbietalk.Utilities;
import bobbietalk.gui.ProgrammingBlock;
import bobbietalk.gui.blocks.EndBlock;
import bobbietalk.semantics.compiler.BlockGraph;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author roberto
 */
public class Interpreter implements Runnable {

    private boolean terminationRequested;

    public enum Status {

        TERMINATED, ERROR, RUNNING, NEVERSTARTED, TERMINATED_BY_REQUEST
    };
    private Socket socket;
    private PrintWriter pw;
    private BufferedReader br;
    private BlockGraph g;
    private List<String> messages = new ArrayList<>();
    private Status status = Status.NEVERSTARTED;

    public Interpreter(Socket socket, BlockGraph g) throws IOException {
        this.socket = socket;
        this.g = g;
        pw = new PrintWriter(socket.getOutputStream());
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    }

    @Override
    public void run() {

        // TOBE UPDATED
        
        
//        ProgrammingBlock block = g.getBeginBlock();
//        ProgrammingBlock loopBeginBlock = null;
//        int loopCounter = -1;
//
//        status = Status.RUNNING;
//
//        while (status == Status.RUNNING && !terminationRequested) {
//
//            ProgrammingBlock nextBlock = block.getNextBlock();
//
//            if (block instanceof RepeatBeginBlock) {
//
//                if (loopBeginBlock != null) {
//                    messages.add("only one loop is supported");
//
//                    status = Status.ERROR;
//
//                } else {
//
//                    RepeatBeginBlock rbb = (RepeatBeginBlock) block;
//
//                    loopBeginBlock = rbb.getNextBlock();
//                    loopCounter = rbb.getValue();
//
//                }
//
//
//            } else if (block instanceof RepeatEndBlock) {
//
//                if (loopBeginBlock == null) {
//                    messages.add("internal error: loop begin not saved");
//
//
//                    status = Status.ERROR;
//                } else {
//
//                    loopCounter--;
//
//                    if (loopCounter > 0) {
//
//                        nextBlock = loopBeginBlock;
//
//                    } else {
//                        loopBeginBlock = null;
//                        loopCounter = -1;
//                    }
//
//                }
//
//            } else if (block instanceof MotorStopBlock) {
//
//                send("off");
//
//            } else if (block instanceof WaitDistanceSensorBlock) {
//
//                WaitDistanceSensorBlock wdsb = (WaitDistanceSensorBlock) block;
//
//                int d = sendAndReceiveInt("readsensor 13"); // telemeter in front
//
//                while ((d == -1 || d >= wdsb.getValue()) && !terminationRequested) {
//                    try {
//                        Thread.sleep(100);
//                        d = sendAndReceiveInt("readsensor 13");
//                    } catch (InterruptedException ex) {
//                        Utilities.getLogger().log(Level.SEVERE, null, ex);
//                        status = Status.ERROR;
//                    }
//
//                }
//
//
//
//            } else if (block instanceof ForwardBlock) {
//
//                send("forward");
//
//            } else if (block instanceof TurnLeftBlock) {
//
//                send("left");
//
//            } else if (block instanceof TurnRightBlock) {
//
//                send("right");
//
//            } else if (block instanceof WaitBlock) {
//
//                WaitBlock wb = (WaitBlock) block;
//                int secs = wb.getValue();
//                try {
//                    Thread.sleep(secs * 1000);
//                } catch (InterruptedException ex) {
//                    messages.add("program interrupted");
//
//                    status = Status.ERROR;
//                }
//
//            } else if (block instanceof EndBlock) {
//                status = Status.TERMINATED;
//            }
//
//            if (status == Status.RUNNING) {
//                block = nextBlock;
//            }
//
//        }
//
//        if (terminationRequested) {
//            status = Status.TERMINATED_BY_REQUEST;
//        }
//
//        send("off");
//        send("bye");

    }

    private void send(String msg) {
        try {

            log("sending:" + msg);
            pw.println(msg);
            pw.flush();

            log("receiving ...");
            final String line = br.readLine();
            log("received:" + line);

            if (line.startsWith("ERROR")) {
                Utilities.getLogger().log(Level.SEVERE, "error reported:" + line);
            }

        } catch (IOException ex) {
            Utilities.getLogger().log(Level.SEVERE, null, ex);
        }


    }

    private int sendAndReceiveInt(String msg) {

        try {

            log("sending:" + msg);
            pw.println(msg);
            pw.flush();

            log("receiving ...");
            final String line = br.readLine();
            log("received:" + line);

            if (line.startsWith("ERROR")) {
                Utilities.getLogger().log(Level.SEVERE, "error reported:" + line);
            } else {
                String[] v = line.split(":");
                return Integer.parseInt(v[1]);
            }

        } catch (IOException ex) {
            Utilities.getLogger().log(Level.SEVERE, null, ex);
        }

        return -2;

    }

    private void log(String msg) {
        System.out.println(msg);
    }

    public List<String> getMessages() {
        return messages;
    }

    public Status getStatus() {
        return status;
    }

    public void terminate() {

        terminationRequested = true;

    }
}
